added Feb 2001 SDK
[windows-sources.git] / shared source / wpf / src / host / shimimpl / lorights.cxx
blob5603d3dba111479e7a14078d710603ae8f3a81a1
1 //+-----------------------------------------------------------------------
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
6 // Description:
7 // This file has all the Low Rights code. This is bascially the code that detects
8 // if the process is running with high privileges and the code that'll restart the
9 // process with low privileges.
11 // One key change from the IE code is that we run restricted by default. The change
12 // is in the function ShouldProcessBeRestricted().
14 // History:
15 // 2005/03/10 - Created the file based on code we got from Anantha Ganjam in the IE team.
16 // 2007/07/06 - [....] - Switched to using the LSA APIs to replace the use of LookupPrivilegeValue()
17 // with a more efficient version for our scenario.
18 // In lieu of SDK documentation of the LSA APIs, there's this KB article:
19 // http://support.microsoft.com/kb/132958.
20 // 2007/09/20-[....]
21 // Ported Windows->DevDiv. See SourcesHistory.txt.
23 //------------------------------------------------------------------------
25 #include "Precompiled.hxx"
26 #include "LoRights.hxx"
27 #include "..\inc\registry.hxx"
29 // <NTLSA.H> Substitute
30 // [Begin]
31 // In Windows we got all these definitions (directly or indirectly) from ntlsa.h, which is not included in
32 // DevDiv's SDK. Trying to transplant it fails because it's apparently incompatible with the DevDiv versions
33 // of other headers. ntddk.h & ntdef.h also contain most of these definitions, but they cause too many
34 // redefinition errors with winnt.h. (There are multiple reports of this happening on the web. People
35 // try to work around by including ntddk.h in a namespace, but that by itself doesn't seem enough.)
37 #include <ntsecapi.h> // This gives us most of what ntlsa.h did in Windows.
39 extern "C"
40 VOID
41 NTAPI
42 RtlInitUnicodeString (
43 PUNICODE_STRING DestinationString,
44 PCWSTR SourceString
48 #ifndef STATUS_SUCCESS
49 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
50 #endif
52 // from ntdef.h
53 #define InitializeObjectAttributes( p, n, a, r, s ) { \
54 (p)->Length = sizeof( LSA_OBJECT_ATTRIBUTES ); \
55 (p)->RootDirectory = r; \
56 (p)->Attributes = a; \
57 (p)->ObjectName = n; \
58 (p)->SecurityDescriptor = s; \
59 (p)->SecurityQualityOfService = NULL; \
61 extern "C" {
62 // from ntlsa.h
63 NTSTATUS
64 NTAPI
65 LsaLookupPrivilegeValue(
66 __in LSA_HANDLE PolicyHandle,
67 __in PLSA_UNICODE_STRING Name,
68 __out PLUID Value
71 //[End]
73 const int cMaxAttrLen = 512;
74 const int cMaxSidName = 512;
76 void FreeSIDArray(__inout_ecount(cSIDs) SID_AND_ATTRIBUTES *pSIDs, unsigned cSIDs)
78 for (DWORD i = 0; i < cSIDs; i++)
80 delete [] static_cast<BYTE*>(pSIDs[i].Sid);
82 delete [] pSIDs;
85 // This is the function that launches our process with restricted tokens
86 BOOL LaunchRestrictedProcess(__in LPCWSTR lpwszCmdLine, __in_ecount(dwDisabledPrivilegeCount) PLUID_AND_ATTRIBUTES pDisabledPrivileges, DWORD dwDisabledPrivilegeCount)
88 BOOL bRet = FALSE;
89 DWORD dwStatus = ERROR_SUCCESS;
90 DWORD dwDisabledSidCount = 0;
91 PSID_AND_ATTRIBUTES pDisabledSids = NULL;
93 // lpwszCmdLine is not traced, because WinMain actually passes NULL.
94 EventWriteWpfHostUm_LaunchingRestrictedProcess();
96 //For the current impementation this returns the list of SIDS in g_disableSIDS
97 // which happens to be Power User and Admin
98 if (ERROR_SUCCESS == (dwStatus = GetDisabledSids( &pDisabledSids, &dwDisabledSidCount)))
100 // if we for some reason we cannot start a restricted process
101 // the only option we have is to start process normally.
102 if (ERROR_SUCCESS == (dwStatus = CreateRestrictedProcess( pDisabledSids,
103 dwDisabledSidCount,
104 pDisabledPrivileges,
105 dwDisabledPrivilegeCount,
106 lpwszCmdLine)))
108 bRet = TRUE;
111 FreeSIDArray(pDisabledSids, dwDisabledSidCount);
113 return bRet;
116 // This functions checks to see the registry if the key to restrict the process is set
117 BOOL ShouldProcessBeRestricted(void)
119 BOOL fRet = TRUE;
120 LONG lRet = ERROR_SUCCESS;
121 HKEY hKey = NULL;
122 DWORD dwUnrestricted = 0;
123 DWORD dwSize = sizeof(dwUnrestricted);
124 OSVERSIONINFOEX osVersion ;
125 osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
127 if ( GetVersionEx( (LPOSVERSIONINFO) & osVersion ) )
129 if ((osVersion.dwMajorVersion == 5) && (osVersion.dwMinorVersion == 1))
131 // We are on XP here, terminate the process if SP level < SP2
132 if (osVersion.wServicePackMajor < 2)
133 ExitProcess(1);
137 // Check the RunUnrestricted registry value.
138 // If it exists and is 0 then run PresentationHost with no restrictions or as the user
139 // If it doesn't exist or if it exists and is set to 1, then run IE in restricted mode
140 lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
141 RegKey_WPF_Hosting,
143 KEY_QUERY_VALUE,
144 &hKey);
146 if (ERROR_SUCCESS == lRet)
148 lRet = RegQueryValueEx( hKey,
149 RegValue_RunUnrestricted,
150 NULL,
151 NULL,
152 (LPBYTE)&dwUnrestricted,
153 &dwSize);
154 if (ERROR_SUCCESS == lRet && dwUnrestricted == 1)
156 fRet = FALSE;
158 RegCloseKey(hKey);
160 return fRet;
163 // The logic here is essentially checking to see of the current process is already restricted
164 // If it is then we do not have to do additional work.
165 BOOL IsCurrentProcessRestricted(__in_ecount(dwDisabledPrivilegesCount) PLUID_AND_ATTRIBUTES pDisabledPrivileges, DWORD dwDisabledPrivilegesCount)
167 static BOOL s_bInit = FALSE;
168 static BOOL s_bRet = TRUE;
170 if (FALSE == s_bInit)
172 // Checks registry to see if this process needs to be disabled
173 if (ShouldProcessBeRestricted())
175 DWORD dwStatus = ERROR_SUCCESS;
176 DWORD dwDisabledSidCount = 0;
177 PSID_AND_ATTRIBUTES pDisabledSids = NULL;
179 // Extract ---- SIDs (currently Admin and power user)
180 if (ERROR_SUCCESS == (dwStatus = GetDisabledSids( &pDisabledSids, &dwDisabledSidCount)))
182 // if the current process is already restricted then we do not need to do anything more
183 if (!IsCurrentPresentationHostRestricted( pDisabledSids,
184 dwDisabledSidCount,
185 pDisabledPrivileges,
186 dwDisabledPrivilegesCount))
188 s_bRet = FALSE;
191 FreeSIDArray(pDisabledSids, dwDisabledSidCount);
193 s_bInit = TRUE;
196 return s_bRet;
199 // This function takes the preset list of restricted groups and priviliges and then
200 // checks to see if any of them exist on the current token.
201 // If they do then the process is not restricted and needs to be restricted.
202 BOOL IsCurrentPresentationHostRestricted(__in PSID_AND_ATTRIBUTES pDisabledSids,
203 __in DWORD dwDisabledSidCount,
204 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges,
205 __in DWORD dwDisabledPrivilegeCount)
207 // If we cannot open a process token for query we cannot generate a restricted token from this token
208 // If we fail here we will try to create a restricted token which is bound to fail
209 // Either case for appcompat we need to just open PresenationHost as-is. If not PresenationHost will never launch
210 BOOL fRet = TRUE;
211 HANDLE hProcToken;
213 // Check if the current PresentationHost is restricted
214 // The restrictions we put on PresenationHost are
215 // 1. Disable in Administrators and Power Users groups
216 // 2. Remove a set of Privileges
217 // If the current token has these settings then we are already in restricted PresentationHost
219 // Open token for the current process , this function actually is quite generic
220 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcToken))
222 // The structure of this API is such that it returns an error to indicate success
223 // when getting size of buffer that needs to be allocated
224 DWORD dwSize = 0;
225 if (!GetTokenInformation(hProcToken, TokenGroupsAndPrivileges, NULL, 0, &dwSize) &&
226 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
228 BYTE userSID[SECURITY_MAX_SID_SIZE];
229 PTOKEN_GROUPS_AND_PRIVILEGES pTokenGroups;
230 pTokenGroups = reinterpret_cast<PTOKEN_GROUPS_AND_PRIVILEGES>(new BYTE[dwSize]);
231 if (!pTokenGroups)
233 fRet = false; // That's a safer way to fail.
235 else
237 // This is a call to query for a token of the process with information on groups and priviliges
238 if ( GetTokenInformation(hProcToken, TokenGroupsAndPrivileges, pTokenGroups, dwSize, &dwSize) &&
239 ERROR_SUCCESS == GetUserSid(hProcToken, &userSID))
241 // If any of our restricted set is part of the groups or priviliges extracted then
242 // this process is not restricted and needs to be stripped.
243 if ( FALSE == CheckForDisabledSids(pTokenGroups->Sids, pTokenGroups->SidCount, pDisabledSids, dwDisabledSidCount) ||
244 FALSE == CheckForRestrictedSids(pTokenGroups->RestrictedSids, pTokenGroups->RestrictedSidCount, pDisabledSids, dwDisabledSidCount, &userSID) ||
245 FALSE == CheckForPrivileges(pTokenGroups->Privileges, pTokenGroups->PrivilegeCount, pDisabledPrivileges, dwDisabledPrivilegeCount))
247 fRet = FALSE;
250 delete [] reinterpret_cast<BYTE*>(pTokenGroups);
253 CloseHandle(hProcToken);
255 return fRet;
259 // This is the function where the actual stripping of the token takes place, it accepts the Groups and priviliges to strip
260 DWORD CreateRestrictedProcess( __in PSID_AND_ATTRIBUTES pDisabledSids,
261 __in DWORD dwDisabledSidCount,
262 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges,
263 __in DWORD dwDisabledPrivilegeCount,
264 __in LPCWSTR lpwszCmdLine)
266 // Get the process token, add disabled SIDs for Administrators and Power Users groups
267 // Also remove the above listed privileges
268 // Create a new PresenationHost process with this token
269 DWORD dwStatus = ERROR_SUCCESS;
270 HANDLE hProcToken = NULL;
271 HANDLE hRestrictedToken = NULL;
273 // Ther current PresentationHost is not restriced, so we create a restricted token that
274 // disables Administrators and Power Users groups if present and removes
275 // a set of Privileges and adds restrictions
276 if (OpenProcessToken(GetCurrentProcess(),
277 TOKEN_READ|TOKEN_WRITE|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE,
278 &hProcToken))
281 // Extracts SID for current user, this is the priviliges that the current process will have, and
282 // even if user is admin or power user we will strip those.
283 BYTE userSID[SECURITY_MAX_SID_SIZE];
284 if (ERROR_SUCCESS == (dwStatus = GetUserSid(hProcToken, &userSID)))
286 // This is where we create a token without the priviliges and groups that we need to disable
287 if (CreateRestrictedToken( hProcToken,
288 0/*WRITE_RESTRICTED*/ ,
289 dwDisabledSidCount,
290 pDisabledSids,
291 dwDisabledPrivilegeCount,
292 pDisabledPrivileges,
293 0, /* dwRestrictedSidCount*/
294 NULL, /* pRestrictedSids*/
295 &hRestrictedToken))
297 WCHAR wszPath[MAX_PATH];
298 LPWSTR pwszArgs = NULL;
299 STARTUPINFO si = { sizeof(si) };
300 PROCESS_INFORMATION pi;
301 GetStartupInfo(&si);
302 ZeroMemory(&pi, sizeof(pi));
303 if (NULL == lpwszCmdLine)
304 pwszArgs = GetCommandLineW();
305 else
306 pwszArgs = (LPWSTR)lpwszCmdLine;
307 if (GetModuleFileNameW(NULL, wszPath, ARRAY_SIZE(wszPath)))
309 // allow access to current user sid
310 PSID pAccessAllowedSIDS[1] = { &userSID };
311 // Allow query and Impersonate permissions to these users on the token
312 if (ERROR_SUCCESS == (dwStatus = AddSidsToToken(hRestrictedToken, pAccessAllowedSIDS, 1 , GENERIC_ALL /*TOKEN_QUERY|TOKEN_IMPERSONATE*/ )))
315 // Launch the process with a restricted token
316 if (CreateProcessAsUser(hRestrictedToken,
317 wszPath,
318 pwszArgs,
319 NULL,
320 NULL,
321 FALSE,
323 NULL,
324 NULL,
325 &si,
326 &pi))
328 WaitForInputIdle(pi.hProcess, 5000);
329 CloseHandle(pi.hProcess);
330 CloseHandle(pi.hThread);
332 else
334 dwStatus = GetLastError();
338 else
340 dwStatus = GetLastError();
342 CloseHandle(hRestrictedToken);
344 else
346 dwStatus = GetLastError();
349 CloseHandle(hProcToken);
352 else
354 dwStatus = GetLastError();
357 return dwStatus;
360 // returns false if any of ---- sids are on the current token list as anything but Deny_only
361 BOOL CheckForDisabledSids(__in PSID_AND_ATTRIBUTES pSids,
362 __in DWORD dwSidCount,
363 __in PSID_AND_ATTRIBUTES pDisabledSids,
364 __in DWORD dwDisabledSidCount)
366 BOOL fRet = TRUE;
367 DWORD dwGroupCount = 0;;
368 DWORD dwCount = 0;
370 for (dwGroupCount=0; dwGroupCount<dwSidCount; dwGroupCount++)
372 for (dwCount=0; dwCount< dwDisabledSidCount; dwCount++)
374 if (EqualSid(pSids[dwGroupCount].Sid, pDisabledSids[dwCount].Sid))
376 if (!(pSids[dwGroupCount].Attributes & SE_GROUP_USE_FOR_DENY_ONLY))
378 fRet = FALSE;
379 break;
384 return fRet;
387 //check if the restricted tokens contain any of the tokens we want to strip
388 BOOL CheckForRestrictedSids(__in PSID_AND_ATTRIBUTES pSids,
389 __in DWORD dwSidCount,
390 __in PSID_AND_ATTRIBUTES pRestrictedSids,
391 __in DWORD dwRestrictedSidCount,
392 __in PSID pUserSid)
394 BOOL fRet = TRUE;
395 DWORD dwGroupCount = 0;;
396 DWORD dwCount = 0;
398 // if current user is admin or power user we need to strip
399 for (dwCount = 0; dwCount < dwRestrictedSidCount; dwCount++)
401 if (EqualSid(pUserSid, pRestrictedSids[dwCount].Sid))
403 fRet = FALSE;
404 break;
408 // if the restricted SIDs contain admin or power user return false since we need to strip
409 if (fRet)
411 for (dwGroupCount = 0; dwGroupCount < dwSidCount; dwGroupCount++)
413 for (dwCount = 0; dwCount < dwRestrictedSidCount; dwCount++)
415 if (EqualSid(pSids[dwGroupCount].Sid, pRestrictedSids[dwCount].Sid))
417 fRet = FALSE;
418 break;
423 return fRet;
427 // This checks to see if any of the priviliges we have predetermined are part of the current list. If they are we return false else true
428 BOOL CheckForPrivileges(__in PLUID_AND_ATTRIBUTES pPrivileges,
429 __in DWORD dwPrivilegeCount,
430 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges,
431 __in DWORD dwDisabledPrivilegeCount)
433 BOOL fRet = TRUE;
434 DWORD dwPrivCount = 0;;
435 DWORD dwCount = 0;
437 for (dwPrivCount=0; dwPrivCount<dwPrivilegeCount; dwPrivCount++)
439 for (dwCount=0; dwCount<dwDisabledPrivilegeCount; dwCount++)
441 if (0 == memcmp(&pPrivileges[dwPrivCount].Luid, &pDisabledPrivileges[dwCount].Luid, sizeof(LUID)))
443 fRet = FALSE;
444 break;
448 return fRet;
451 // Iterates over the predefined list of disabled SIDs we have and obtains the SID values for them.
452 // Call FreeSIDArray() when done with the returned data.
453 DWORD GetDisabledSids(__out PSID_AND_ATTRIBUTES *ppDisabledSids, __out DWORD *pdwDisabledSidCount)
455 DWORD dwStatus = ERROR_SUCCESS;
456 DWORD dwCount;
457 DWORD dwSidSize;
458 PSID_AND_ATTRIBUTES pDisabledSids;
460 pDisabledSids = new SID_AND_ATTRIBUTES[ARRAY_SIZE(g_disableSIDS)];
461 if (pDisabledSids)
463 memset(pDisabledSids, 0, (ARRAY_SIZE(g_disableSIDS))*sizeof(SID_AND_ATTRIBUTES));
464 for (dwCount=0; dwCount<ARRAY_SIZE(g_disableSIDS); dwCount++)
466 pDisabledSids[dwCount].Sid = new BYTE[SECURITY_MAX_SID_SIZE];
467 if (pDisabledSids[dwCount].Sid)
469 dwSidSize = SECURITY_MAX_SID_SIZE;
470 if (!CreateWellKnownSid(g_disableSIDS[dwCount], NULL, pDisabledSids[dwCount].Sid, &dwSidSize))
472 dwStatus = GetLastError();
473 break;
476 else
478 dwStatus = ERROR_NOT_ENOUGH_MEMORY;
479 break;
483 if (dwStatus == ERROR_SUCCESS)
485 *ppDisabledSids = pDisabledSids;
486 *pdwDisabledSidCount = ARRAY_SIZE(g_disableSIDS);
488 else
490 FreeSIDArray(pDisabledSids, ARRAY_SIZE(g_disableSIDS));
493 else
495 dwStatus = ERROR_NOT_ENOUGH_MEMORY;
497 return dwStatus;
500 //This call gets a list of disabled priviliges
501 DWORD GetDisabledPrivileges(__out PLUID_AND_ATTRIBUTES *ppDisabledPrivileges, __out DWORD *pdwDisabledPrivlegeCount)
503 DWORD dwStatus = ERROR_SUCCESS;
504 DWORD dwCount;
505 *ppDisabledPrivileges = NULL;
506 *pdwDisabledPrivlegeCount = 0;
507 PLUID_AND_ATTRIBUTES pDisabledPrivileges;
509 pDisabledPrivileges = new LUID_AND_ATTRIBUTES[ARRAY_SIZE(g_ppwszPrivileges)];
510 if (pDisabledPrivileges)
512 NTSTATUS ntStatus;
513 LSA_HANDLE PolicyHandle;
514 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
515 InitializeObjectAttributes(&ObjectAttributes, NULL, 0L, NULL, NULL);
517 // Instead of calling LookupPrivilegeValue call LsaLookupPrivilegeValue
518 // to avoid LsaOpenPolicy/LsaClose inside the loop.
519 ntStatus = LsaOpenPolicy(NULL,
520 &ObjectAttributes,
521 POLICY_LOOKUP_NAMES,
522 &PolicyHandle);
523 if (ntStatus == STATUS_SUCCESS)
525 UNICODE_STRING uName;
526 for(dwCount=0; dwCount<ARRAY_SIZE(g_ppwszPrivileges); dwCount++)
528 // Initialize a counted string for LsaLookupPrivilegeValue. The buffer of uName points to the WSTR argument
529 RtlInitUnicodeString(&uName, g_ppwszPrivileges[dwCount]);
530 ntStatus = LsaLookupPrivilegeValue(PolicyHandle, &uName, &pDisabledPrivileges[dwCount].Luid);
531 if (ntStatus != STATUS_SUCCESS)
533 dwStatus = LsaNtStatusToWinError(ntStatus);
534 break;
538 ntStatus = LsaClose(PolicyHandle);
539 if (ntStatus != STATUS_SUCCESS)
541 dwStatus = LsaNtStatusToWinError(ntStatus);
544 else
546 dwStatus = LsaNtStatusToWinError(ntStatus);
549 if (dwStatus == ERROR_SUCCESS)
551 *ppDisabledPrivileges = pDisabledPrivileges;
552 *pdwDisabledPrivlegeCount = ARRAY_SIZE(g_ppwszPrivileges);
554 else
556 delete [] pDisabledPrivileges;
559 else
561 dwStatus = ERROR_NOT_ENOUGH_MEMORY;
564 return dwStatus;
567 //Extracts the user sid for the process
568 DWORD GetUserSid(__in HANDLE hProcToken, __out_bcount(SECURITY_MAX_SID_SIZE) PSID pSid)
570 DWORD dwError = ERROR_SUCCESS;
571 DWORD cbTokenInfo = 0;
573 // GetTokenInformation(TokenUser) pupulates a TOKEN_USER structure immediately followed by a
574 // SID structure. TOKEN_USER::User.Sid points to the adjoined SID structure.
575 BYTE buffer[sizeof TOKEN_USER + SECURITY_MAX_SID_SIZE];
576 TOKEN_USER *pTokenUser = reinterpret_cast<TOKEN_USER*>(buffer);
577 if (GetTokenInformation(hProcToken, TokenUser, pTokenUser, sizeof buffer, &cbTokenInfo))
579 CopySid(SECURITY_MAX_SID_SIZE, pSid, pTokenUser->User.Sid);
581 else
583 dwError = GetLastError();
585 return dwError;
589 // This call adds a list of sids to a token
590 DWORD AddSidsToToken(__in HANDLE hRestrictedToken, __in PSID *ppSids, __in DWORD dwSids, __in DWORD dwAccess)
592 PACL pOldDacl = NULL;
593 PACL pNewDacl = NULL;
594 BOOL fDaclPresent;
595 BOOL fDaclDefaulted;
596 DWORD cbSD = 0;
597 DWORD dwError = ERROR_SUCCESS;
598 PSECURITY_DESCRIPTOR pSD = NULL;
600 // GetKernelObjectSecurity() appends various SIDs to a SECURITY_DESCRIPTOR header.
601 // We first query for the needed space.
602 if (!GetKernelObjectSecurity(hRestrictedToken, DACL_SECURITY_INFORMATION, NULL, cbSD, &cbSD) &&
603 (dwError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)
605 pSD = reinterpret_cast<PSECURITY_DESCRIPTOR>(new BYTE[cbSD]);
606 if (pSD)
608 dwError = ERROR_SUCCESS;
609 if (GetKernelObjectSecurity(hRestrictedToken, DACL_SECURITY_INFORMATION, pSD, cbSD, &cbSD))
611 if (GetSecurityDescriptorDacl(pSD, &fDaclPresent, &pOldDacl, &fDaclDefaulted))
613 DWORD cbDacl = 0;
614 if (ERROR_SUCCESS == (dwError = SetSidsOnAcl(ppSids, dwSids, pOldDacl, &pNewDacl, &cbDacl, dwAccess, 0)))
616 DWORD cbTokenInfo;
617 TOKEN_DEFAULT_DACL tokenDefaultDACL;
619 tokenDefaultDACL.DefaultDacl = pNewDacl;
620 cbTokenInfo = sizeof(tokenDefaultDACL)+cbDacl;
622 if (!SetTokenInformation(hRestrictedToken, TokenDefaultDacl, &tokenDefaultDACL, cbTokenInfo))
624 dwError = GetLastError();
626 delete pNewDacl;
629 else
631 dwError = GetLastError();
634 else
636 dwError = GetLastError();
638 delete [] reinterpret_cast<BYTE*>(pSD);
640 else
642 dwError = ERROR_NOT_ENOUGH_MEMORY;
646 return dwError;
649 //gives access to built in users and current users, current value passed in also includes IEGroup but that must die.
650 BOOL SetSidsOnAcl(__in PSID *ppSids,
651 __in DWORD dwSids,
652 __in PACL pAclSource,
653 __out PACL *pAclDestination,
654 __out DWORD *pcbDacl,
655 __in DWORD AccessMask,
656 __in BYTE AceFlags)
658 DWORD dwError = ERROR_SUCCESS;
659 DWORD dwNewAclSize;
660 DWORD AceCounter;
661 __bound DWORD iSid;
662 PACCESS_ALLOWED_ACE pAce;
664 ACL_SIZE_INFORMATION AclInfo;
666 if (pAclSource != NULL)
668 if (GetAclInformation(pAclSource, &AclInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
670 // compute size for new Acl, based on addition or subtraction of Ace
671 dwNewAclSize = AclInfo.AclBytesInUse;
672 HRESULT hr;
674 for (iSid = 0; iSid < dwSids; iSid++)
676 DWORD addend = GetLengthSid(ppSids[iSid]);
677 C_ASSERT(sizeof(ACCESS_ALLOWED_ACE) >= sizeof(DWORD));
678 hr = DWordAdd(addend, sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD), &addend);
679 if (FAILED(hr))
681 return ERROR_INVALID_DATA;
683 hr = DWordAdd(dwNewAclSize, addend, &dwNewAclSize);
684 if (FAILED(hr))
686 return ERROR_INVALID_DATA;
690 *pAclDestination = reinterpret_cast<PACL>(new BYTE[dwNewAclSize]);
691 if (*pAclDestination)
693 *pcbDacl = dwNewAclSize;
694 // initialize new Acl
695 if (InitializeAcl(*pAclDestination, dwNewAclSize, ACL_REVISION))
697 for (iSid = 0; iSid < dwSids; iSid++)
699 // if appropriate, add ace representing pSid
700 PACCESS_ALLOWED_ACE pNewAce;
701 if (AddAccessAllowedAce(*pAclDestination, ACL_REVISION, AccessMask, ppSids[iSid]))
703 // get pointer to ace we just added, so we can change the AceFlags
704 if (GetAce(*pAclDestination, iSid, (void**)&pNewAce))
705 pNewAce->Header.AceFlags = AceFlags;
706 else
708 dwError = GetLastError();
709 break;
712 else
714 dwError = GetLastError();
715 break;
718 if (ERROR_SUCCESS == dwError)
720 // copy existing aces to new Acl
721 for (AceCounter = 0 ; AceCounter < AclInfo.AceCount ; AceCounter++)
723 // fetch existing ace
724 if (GetAce(pAclSource, AceCounter, (LPVOID*) & pAce))
726 if (!AddAce(*pAclDestination, ACL_REVISION, MAXDWORD, pAce, ((PACE_HEADER)pAce)->AceSize))
728 dwError = GetLastError();
729 break;
732 else
734 dwError = GetLastError();
735 break;
740 else
742 dwError = GetLastError();
745 else
747 dwError = ERROR_NOT_ENOUGH_MEMORY;
750 else
752 dwError = GetLastError();
755 else
757 *pAclDestination = NULL;
758 *pcbDacl = 0;
761 if (dwError != ERROR_SUCCESS && *pAclDestination)
763 delete *pAclDestination;
764 *pAclDestination = NULL;
767 return dwError;
770 BOOL IsPresentationHostHighIntegrity()
772 DWORD pid = GetCurrentProcessId();
773 return GetProcessIntegrityLevel(pid) >= (int)SECURITY_MANDATORY_HIGH_RID;